package com.taotao.enums.validate;

import com.taotao.enums.utils.BaseEnumUtils;
import com.taotao.enums.BaseEnum;
import com.taotao.enums.EnumHub;
import com.taotao.enums.annotation.EnumId;
import com.taotao.enums.annotation.EnumField;
import com.taotao.enums.utils.StringUtil;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Collection;


/**
 * 自定义的校验注解验证类，验证传入值是否符合枚举。可用于基本数据类型及包装类、数组类型、集合类型和带分隔符的字符串
 */
public class EnumFieldValidator implements ConstraintValidator<EnumField, Object> {


    private EnumField enumField;

    @Override
    public void initialize(EnumField enumField) {
        this.enumField = enumField;
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        if (value == null) {
            return Boolean.TRUE;
        }

        if (enumField.value().isAssignableFrom(CharSequence.class) && isBlank((CharSequence) value)) {
            return Boolean.TRUE;
        }


        Class<? extends BaseEnum> enumClass = enumField.value();
        EnumId enumId = enumClass.getAnnotation(EnumId.class);

        if (null != enumId) {
            enumClass = EnumHub.getEnumClass(enumId.value());
        }

        if (StringUtil.isBlank(enumField.separator())) {

            Class<?> fieldClass = value.getClass();
            if (fieldClass.isArray() || value instanceof Collection) {
                // 数组集合处理
                if (fieldClass.isArray()) {
                    // 数组集合处理
                    Object[] arr = (Object[]) value;
                    for (Object o : arr) {
                        BaseEnum e = BaseEnumUtils.getByCode(enumClass, o);
                        if (null == e) {
                            if (StringUtil.isBlank(enumField.message())) {
                                //重写错误提示
                                context.disableDefaultConstraintViolation();
                                context.buildConstraintViolationWithTemplate("参数值不在枚举范围,枚举范围：" + BaseEnumUtils.getDscr(enumClass)
                                        + "。当前值：[" + value + "],包含错误值:" + o).addConstraintViolation();
                            }

                            return false;
                        }


                    }
                    return true;

                }

                if (value instanceof Collection) {
                    // 数组集合处理
                    Collection<?> coll = (Collection<?>) value;
                    for (Object o : coll) {
                        BaseEnum e = BaseEnumUtils.getByCode(enumClass, o);
                        if (null == e) {
                            if (StringUtil.isBlank(enumField.message())) {
                                //重写错误提示
                                context.disableDefaultConstraintViolation();
                                context.buildConstraintViolationWithTemplate("参数值不在枚举范围,枚举范围：" + BaseEnumUtils.getDscr(enumClass)
                                        + "。当前值：[" + value + "],包含错误值:" + o).addConstraintViolation();
                            }

                            return false;
                        }


                    }
                    return true;

                }
                if (value.getClass().isArray()) {
                    // 数组集合处理
                    Object[] coll = (Object[]) value;
                    for (Object o : coll) {
                        BaseEnum e = BaseEnumUtils.getByCode(enumClass, o);
                        if (null == e) {
                            if (StringUtil.isBlank(enumField.message())) {
                                //重写错误提示
                                context.disableDefaultConstraintViolation();
                                context.buildConstraintViolationWithTemplate("参数值不在枚举范围,枚举范围：" + BaseEnumUtils.getDscr(enumClass)
                                        + "。当前值：[" + value + "],包含错误值:" + o).addConstraintViolation();
                            }

                            return false;
                        }


                    }
                    return true;

                }


            } else {
                String displayName = BaseEnumUtils.getDisplayName(enumClass, value);
                if (null != displayName) {
                    return true;
                }

                if (StringUtil.isBlank(enumField.message())) {
                    //重写错误提示
                    context.disableDefaultConstraintViolation();
                    context.buildConstraintViolationWithTemplate("参数值不在枚举范围,枚举范围：" + BaseEnumUtils.getDscr(enumClass) + "。当前值：" + value).addConstraintViolation();
                }

                return false;
            }


        } else {
            if (value instanceof String) {
                String s = (String) value;
                if (StringUtil.isBlank(s)) {
                    return true;
                }

                String[] arr = s.split(enumField.separator());
                for (String ss : arr) {
                    BaseEnum e = BaseEnumUtils.getByCodeStr(enumClass, ss);
                    if (null != e) {
                        return true;
                    }

                    if (StringUtil.isBlank(enumField.message())) {
                        //重写错误提示
                        context.disableDefaultConstraintViolation();
                        context.buildConstraintViolationWithTemplate("参数值不在枚举范围,枚举范围：" + BaseEnumUtils.getDscr(enumClass) + "。当前值：[" + value + "],包含错误值:" + ss).addConstraintViolation();
                    }

                    return false;
                }


            } else {
                throw new IllegalStateException("非String字段EnumField的separator无效");
            }

        }


        return false;
    }

    public static boolean isBlank(final CharSequence cs) {
        int strLen;
        if (cs == null || (strLen = cs.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(cs.charAt(i))) {
                return false;
            }
        }
        return true;
    }


}
